#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <sstream>

#include "Log.hpp"

using namespace My_Log;

const std::string sepline = "\r\n";
const std::string sepheard = ": ";
const std::string sepblank = " ";
const std::string defver = "HTTP/1.0";

class HttpRequest
{
public:
    HttpRequest()
    {
    }

    void Deserialize(std::string &req)
    {
        // 解析状态行
        int pos = req.find(sepline);
        if (pos == std::string::npos)
        {
            LOG(LogLevel::WARNING) << "find err!";
            return;
        }
        std::string firstline = req.substr(0, pos);
        std::stringstream ss(firstline);
        req.erase(0, pos + sepline.size());
        ss >> _method >> _uri >> _ver;
        LOG(LogLevel::DEBUG) << "  #  " << _method << "  #  " << _uri << "  #  " << _ver;

        pos = _uri.find("?");
        if (pos == std::string::npos)
        {
            _isexec = false;
            _path = _uri;
            _args = "";
        }
        else
        {
            _isexec = true;
            _path = _uri.substr(0, pos);
            _args = _uri.substr(pos + 1);
        }

        // 解析报头
        while (true)
        {
            // 解析报头中的一行
            int p1 = req.find(sepline);
            if (p1 == std::string::npos)
            {
                LOG(LogLevel::WARNING) << "find err";
                return;
            }
            std::string line = req.substr(0, p1);
            req.erase(0, p1 + sepline.size());

            // 遇到空行跳出循环
            if (line.empty())
                break;

            // 一行中的kv值
            int p2 = line.find(sepheard);
            if (p2 == std::string::npos)
            {
                LOG(LogLevel::WARNING) << "find err";
                return;
            }
            std::string key = line.substr(0, p2);
            line.erase(0, p2 + sepheard.size());
            _heardkv.insert(std::pair<std::string, std::string>(key, line));
        }

        // 空行
        _empline = sepline;

        // 正文
        _body = req;
    }

    void LOGPrint()
    {
        LOG(LogLevel::DEBUG) << "method: " << _method;
        LOG(LogLevel::DEBUG) << "path: " << _uri;
        LOG(LogLevel::DEBUG) << "ver: " << _ver;

        for (auto &h : _heardkv)
        {
            LOG(LogLevel::DEBUG) << h.first << "-----" << h.second;
        }
        LOG(LogLevel::DEBUG) << "empline: " << _empline;
        LOG(LogLevel::DEBUG) << "body: " << _body;
    }
    std::string GetMethod() const { return _method; }
    std::string GetUri() const { return _uri; }
    std::string GetPath() const { return _path; }
    std::string GetVer() const { return _ver; }
    std::string GetBody() const { return _body; }

    ~HttpRequest()
    {
    }

private:
    // 客户端发来的http请求解析后的数据
    std::string _method;
    std::string _uri;
    std::string _path;
    std::string _args;
    std::string _ver;
    std::unordered_map<std::string, std::string> _heardkv;
    std::string _empline;
    std::string _body;

    bool _isexec;
};

class HttpResponse
{
private:
    std::string StatusCTOS(const std::string &code) const
    {
        if (code == "200")
            return "OK";
        else if (code == "404")
            return "Not Found";
        else
            return std::string();
    }

public:
    HttpResponse() : _empline(sepline), _ver(defver)
    {
    }

    void Serialize(std::string &resp)
    {
        // 序列化状态行
        resp = _ver + sepblank + _status_code + sepblank + _status_str + sepline;
        // 序列化报头
        for (auto &h : _heardkv)
        {
            resp += h.first + sepheard + h.second + sepline;
        }
        // 序列化空行
        resp += _empline;
        // 序列化正文
        resp += _body;
    }

    void LOGPrint()
    {
        LOG(LogLevel::DEBUG) << "ver: " << _ver;
        LOG(LogLevel::DEBUG) << "status_code: " << _status_code;
        LOG(LogLevel::DEBUG) << "status_str: " << _status_str;

        for (auto &h : _heardkv)
        {
            LOG(LogLevel::DEBUG) << h.first << "-----" << h.second;
        }

        LOG(LogLevel::DEBUG) << "empline: " << _empline;
        LOG(LogLevel::DEBUG) << "body: " << _body;
    }

    std::string GetVer() const { return _ver; }
    std::string GetStatusCode() const { return _status_code; }
    std::string GetStatusStr(const std::string &code) const { return StatusCTOS(code); }
    std::string GetHeardKV(const std::string &k) { return _heardkv[k]; }
    std::string GetBody() const { return _body; }

    void SetVer(const std::string &ver) { _ver = ver; }
    void SetStatusCode(const std::string &code)
    {
        _status_code = code;
        _status_str = StatusCTOS(code);
    }
    void SetHeardKV(const std::string &k, const std::string &v)
    {
        _heardkv.insert(std::pair<std::string, std::string>(k, v));
    }
    void SetBody(const std::string &body) { _body = body; }

    ~HttpResponse()
    {
    }

private:
    std::string _ver;
    std::string _status_code;
    std::string _status_str;
    std::unordered_map<std::string, std::string> _heardkv;
    std::string _empline;
    std::string _body;
};